package com.wang.cloud.common.mysql.aspects;

import com.wang.cloud.common.mysql.annotations.DynamicDB;
import com.wang.cloud.common.mysql.config.AutoDynamicDataSource;
import com.wang.cloud.common.mysql.utils.DataSourceContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Method;
import java.util.Objects;

/**
 * 实现@DynamicDB注解的AOP切面
 *
 * @author wang ye
 * @date 2024/6/27
 */
@Aspect
@Slf4j
public class MyDynamicDataSourceAspect {

    private AutoDynamicDataSource autoDynamicDataSource;

    public MyDynamicDataSourceAspect(@Autowired(required = false) AutoDynamicDataSource autoDynamicDataSource) {
        this.autoDynamicDataSource = autoDynamicDataSource;
    }

    @Pointcut("@within(com.wang.cloud.common.mysql.annotations.DynamicDB) " +
            "|| @annotation(com.wang.cloud.common.mysql.annotations.DynamicDB)")
    public void dynamicDataSource() {
    }

    @Around("dynamicDataSource()")
    public Object datasourceAround(ProceedingJoinPoint point) throws Throwable {
        String dataSource = getDataSource(point);
        if (Objects.nonNull(dataSource)) {
            DataSourceContextHolder.setDataSource(dataSource);
        }
        try {
            return point.proceed();
        } finally {
            DataSourceContextHolder.removeDataSource();
        }
    }

    /**
     * 获取数据源
     *
     * @param point
     * @return
     */
    private String getDataSource(ProceedingJoinPoint point) {
        DynamicDB annotation = getAnnotation(point);
        String dataSource = annotation.value();
        if (StringUtils.isNoneEmpty(dataSource)) {
            return dataSource;
        }
        if (Objects.nonNull(autoDynamicDataSource)) {
            return autoDynamicDataSource.getDataSource();
        }
        return "default";
    }

    /**
     * 获取注解
     *
     * @param point
     * @return
     */
    private DynamicDB getAnnotation(ProceedingJoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        DynamicDB dynamicDB = method.getAnnotation(DynamicDB.class);
        if (Objects.nonNull(dynamicDB)) {
            return dynamicDB;
        }
        dynamicDB = point.getTarget()
                .getClass()
                .getAnnotation(DynamicDB.class);
        return dynamicDB;
    }

}
